using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using xml = System.Xml;
using Sixeyed.CacheAdapter.Interfaces;
using System.ComponentModel;
using System.Drawing.Design;

namespace Sixeyed.CacheAdapter.Management
{
    /// <summary>
    /// Represents the TransmitLocation configuration used in the adapter
    /// </summary>
    /// <remarks>
    /// 1. Note the management framework does not include a namespace in the generated
    /// XML for the config, so the schema and this object are defined without one.
    /// 2. This class includes System.ComponentModel attributes so it can be used for
    /// property pages outside of the Management Console (which uses atributes in the XSD).
    /// </remarks>
    [Serializable]
    [XmlRoot(ElementName = "Config")]
    public class TransmitLocation
    {
        private static TransmitLocation _current;

        /// <summary>
        /// Gets/sets a static <see cref="TransmitLocation"/> instance, for state to be shared
        /// </summary>
        public static TransmitLocation Current
        {
            get
            {
                if (_current == null)
                {
                    _current = new TransmitLocation();
                }
                return _current;
            }
            set
            {
                _current = value;
            }
        }

        private string _uri;
        private string _name;
        private string _provider;
        private string _configuration;

        /// <summary>
        /// Gets/sets the endpoint uri - composed of cache provider and transmit location name
        /// </summary>
        /// <example>
        /// cache://NCacheExpressProvider/ShortTermCacheInstance
        /// </example>
        [Browsable(false)]
        [XmlElement(ElementName = "uri")]
        public string Uri
        {
            get { return _uri; }
            set { _uri = value; }
        }

        /// <summary>
        /// Gets/sets the transmit location name
        /// </summary>
        [DisplayName("Name")]
        [Description("Name of the cache instance")]
        [Category("Properties")]
        [XmlElement(ElementName = "name")]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// Gets/sets the fully-qualified type name of the cache provider
        /// </summary>
        [DisplayName("Cache Provider")]
        [Description("Type of the Cache Provider")]
        [Category("Provider")]
        [Editor(typeof(UITypeEditors.CacheProviderTypeName), typeof(UITypeEditor))]
        [TypeConverter(typeof(Converters.CacheProviderTypeName))]
        [XmlElement(ElementName = "provider")]
        public string Provider
        {
            get { return _provider; }
            set { _provider = value; }
        }

        /// <summary>
        /// Gets/sets the configuration of the cache instance
        /// </summary>
        [DisplayName("Configuration")]
        [Description("Configuration of the cache instance")]
        [Category("Provider")]
        [Editor(typeof(UITypeEditors.CacheProviderConfiguration), typeof(UITypeEditor))]
        [TypeConverter(typeof(Converters.CacheProviderConfiguration))]
        [XmlElement(ElementName = "configuration")]
        public string Configuration
        {
            get { return _configuration; }
            set { _configuration = value; }
        }

        /// <summary>
        /// Returns an XML-serialized string of the object
        /// </summary>
        /// <param name="location">TransmitLocation object</param>
        /// <returns>XML string</returns>
        public static string Serialize(TransmitLocation location)
        {
            string xml = null;
            using (MemoryStream stream = new MemoryStream())
            {
                XmlSerializer serializer = new XmlSerializer(typeof(TransmitLocation));
                serializer.Serialize(stream, location);
                stream.Position = 0;
                StreamReader reader = new StreamReader(stream);
                xml = reader.ReadToEnd();
            }
            return xml;
        }

        /// <summary>
        /// Returns a <see cref="TransmitLocation"/> object from an XML string
        /// </summary>
        /// <param name="xml">XML string</param>
        /// <returns>TrtansmitLocation object</returns>
        public static TransmitLocation Deserialize(string xml)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(TransmitLocation));
            StringReader reader = new StringReader(xml);
            TransmitLocation locationConfig = (TransmitLocation)serializer.Deserialize(reader);
            return locationConfig;
        }

        /// <summary>
        /// Returns the type of the cache configuration for the location
        /// </summary>
        /// <returns>ICacheProviderConfiguration type</returns>
        public Type GetCacheConfigurationType()
        {
            Type providerType = Type.GetType(this.Provider);
            ICacheProvider provider = Activator.CreateInstance(providerType) as ICacheProvider;
            Type configurationType = provider.GetConfigurationType();
            return configurationType;
        }
        
        /// <summary>
        /// Returns an XmlSerializer for the cache configuration type of the location
        /// </summary>
        /// <returns>XmlSerializer</returns>
        public XmlSerializer GetCacheConfigurationSerializer()
        {
            return new XmlSerializer(GetCacheConfigurationType());
        }

        /// <summary>
        /// Returns the cache configuration for the location
        /// </summary>
        /// <returns>ICacheProviderConfiguration</returns>
        public ICacheProviderConfiguration GetCacheConfiguration()
        {
            XmlSerializer serializer = GetCacheConfigurationSerializer();
            StringReader reader = new StringReader(this.Configuration);
            ICacheProviderConfiguration config = serializer.Deserialize(reader) as ICacheProviderConfiguration;
            return config;
        }
    }
}
